/*
 * @Author: xiaosihan 
 * @Date: 2024-05-22 01:40:12 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-05-29 16:04:29
 */

import { round } from "lodash";
import { AdditiveBlending, BufferAttribute, BufferGeometry, Clock, Color, DoubleSide, GridHelper, Group, Line, LineBasicMaterial, Mesh, MeshBasicMaterial, MeshLambertMaterial, NormalBlending, PlaneGeometry, Points, PointsMaterial, SRGBColorSpace, ShaderMaterial, Shape, ShapeGeometry, Vector2, Vector3 } from "three";
import threeLoader from "three-base/threeLoader";
import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils";
import GeojsonLine from "../GeojsonLine";
import GeojsonMesh from "../GeojsonMesh";
import Annular from "./Annular";
import animateMOV from "./animate.mov?url";
import animate2MOV from "./animate2.mov?url";
import chinaJSON from "./china.json";
import chinaBlurLinePNG from "./chinaBlurLine.png";
import oceanBgPNG from "./ocean-bg.png";
import rotationBorder1PNG from "./rotationBorder1.png";
import rotationBorder2PNG from "./rotationBorder2.png";
import keyContorls from "three-base/keyContorls";
import HtmlLableReflextion from "../HtmlLableReflextion/HtmlLableReflextion";
import labelIconPNG from "./label-icon.png";
import Particles from "./Particles/Particles";
import { autorun } from "mobx";
import homeStore from "@views/home/homeStore";
import threeUtils from "three-base/threeUtils";
import Transition from "three-base/Transition";



// 地板网格对象
export default class FloorGrid extends Group {
    constructor() {
        super();
    }

    //网格辅助线
    gridHelp = (() => {
        const gridHelp = new GridHelper(100, 20, 0x28373a, 0x28373a);
        this.add(gridHelp);
        return gridHelp;
    })();


    // 创建+号阵列
    shapeMesh = (() => {
        const gridSize = 100;
        const gridDivision = 20;
        const shapeColor = "#288686";
        let shapeSpace = gridSize / gridDivision
        let range = gridSize / 2
        let shapeMaterial = new MeshBasicMaterial({ color: shapeColor, side: DoubleSide })
        let shapeGeometrys = []
        for (let i = 0; i < gridDivision + 1; i++) {
            for (let j = 0; j < gridDivision + 1; j++) {
                let shapeSize = 1;
                let w = shapeSize / 6 / 3
                let h = shapeSize / 3
                let points = [
                    new Vector2(-h, -w),
                    new Vector2(-w, -w),
                    new Vector2(-w, -h),
                    new Vector2(w, -h),
                    new Vector2(w, -h),
                    new Vector2(w, -w),
                    new Vector2(h, -w),
                    new Vector2(h, w),
                    new Vector2(w, w),
                    new Vector2(w, h),
                    new Vector2(-w, h),
                    new Vector2(-w, w),
                    new Vector2(-h, w),
                ]
                let shape = new Shape(points)
                let shapeGeometry = new ShapeGeometry(shape, 24);
                shapeGeometry.translate(-range + i * shapeSpace, -range + j * shapeSpace, 0)
                shapeGeometrys.push(shapeGeometry)
            }
        }

        let geometry = BufferGeometryUtils.mergeGeometries(shapeGeometrys)
        let shapeMesh = new Mesh(geometry, shapeMaterial)
        shapeMesh.renderOrder = -1
        shapeMesh.rotateX(-Math.PI / 2)
        shapeMesh.position.y -= 0.1;
        this.add(shapeMesh);
        return shapeMesh;
    })();

    //地板中心价格渐变色的正方形
    plane = (() => {
        let geometry = new PlaneGeometry(20, 20)
        const texture = threeLoader.getTexture(oceanBgPNG);
        texture.colorSpace = SRGBColorSpace;
        let material = new MeshBasicMaterial({
            map: texture,
            opacity: 1,
            transparent: true
        })
        let plane = new Mesh(geometry, material)
        plane.rotateX(-Math.PI / 2)
        plane.position.set(0, -1, 0)
        this.add(plane);
    })();

    //中国地图模糊轮廓线贴图
    chinaBlurLine = (() => {
        let geometry = new PlaneGeometry(147, 147)
        const texture = threeLoader.getTexture(chinaBlurLinePNG);
        texture.colorSpace = SRGBColorSpace;
        let material = new MeshBasicMaterial({
            color: 0x3c92a4,
            alphaMap: texture,
            transparent: true,
            opacity: 0.5,
        })
        let plane = new Mesh(geometry, material)
        plane.rotateX(-Math.PI / 2)
        plane.scale.set(2.4, 2, 2);
        plane.position.set(-60.3, -0.9, 45.6)
        this.add(plane);
    })();

    //旋转的圆环1
    annular1 = (() => {
        let max = 12
        const texture = threeLoader.getTexture(rotationBorder1PNG);
        texture.colorSpace = SRGBColorSpace;
        const annular = new Annular({
            map: texture,
            width: max * 1.178,
            rotateSpeed: 0.01,
            opacity: 0.2,
        });
        annular.position.set(0, 0.28, 0);
        annular.renderOrder = 1;
        this.add(annular);
        return annular;
    })();

    //旋转的圆环2
    annular2 = (() => {
        let max = 12
        const texture = threeLoader.getTexture(rotationBorder2PNG);
        texture.colorSpace = SRGBColorSpace;
        const annular = new Annular({
            map: texture,
            width: max * 1.116,
            rotateSpeed: -0.04,
            opacity: 0.4,
        });
        annular.position.set(0, 0.01, 0);
        annular.renderOrder = 1;
        this.add(annular);
        return annular;
    })();

    //视频动画对象1
    videoPlane1 = (() => {
        const texture = threeLoader.getTexture(animateMOV);
        texture.colorSpace = SRGBColorSpace
        let scale = 1.2
        let geometry = new PlaneGeometry(2.5, 1);
        let material = new MeshBasicMaterial({
            color: 0xa4e7f6,
            alphaMap: texture,
            transparent: true,
            opacity: 1,
            blending: AdditiveBlending,
        })
        let mesh = new Mesh(geometry, material)
        mesh.rotateX(-Math.PI / 2)
        mesh.position.set(11, 0.4, 1);
        mesh.renderOrder = 10
        this.add(mesh);
        return mesh;
    })();

    //视频动画对象2
    videoPlane2 = (() => {
        const texture = threeLoader.getTexture(animate2MOV);
        texture.colorSpace = SRGBColorSpace
        let scale = 1.2
        let geometry = new PlaneGeometry(2.5, 1);
        let material = new MeshBasicMaterial({
            color: 0xa4e7f6,
            alphaMap: texture,
            transparent: true,
            opacity: 1,
            blending: AdditiveBlending,
        })
        let mesh = new Mesh(geometry, material)
        mesh.rotateX(-Math.PI / 2)
        mesh.position.set(-11, 0.4, 2);
        mesh.renderOrder = 10
        this.add(mesh);
        return mesh;
    })();

    //中国地图模型
    chinaMesh = (() => {
        const scale = 5;
        const chinaMesh = new GeojsonMesh(chinaJSON);
        chinaMesh.scale.set(scale, scale, scale);
        chinaMesh.position.set(-116.468994140625 * scale, 0, 40.25177764892578 * scale);

        chinaMesh.traverse(obj => {
            if ((obj as Mesh).isMesh) {
                (obj as Mesh).material = new MeshLambertMaterial({
                    side: DoubleSide,
                    color: "#122a32",
                    transparent: true,
                    opacity: 0.7
                });
            }
        })

        this.add(chinaMesh);
        return chinaMesh;
    })();

    //中国地图轮廓
    chinaLine = (() => {
        const scale = 5;
        const chinaLine = new GeojsonLine(chinaJSON);
        chinaLine.scale.set(scale, scale, scale);
        chinaLine.position.set(-116.468994140625 * scale, 0, 40.25177764892578 * scale);

        chinaLine.traverse(obj => {
            if ((obj as Line).isLine) {
                ((obj as Line).material as LineBasicMaterial).color.set("#3c92a4");
            }
        });
        this.add(chinaLine);
        return chinaLine;
    })();

    // 粒子特效
    particles = (() => {
        const particles = new Particles({
            num: 100, // 粒子数量
            range: 30, // 范围
            dir: "up",
            speed: 0.1,
        });
        particles.rotation.x = -Math.PI / 2;
        this.add(particles);
        return particles;
    })();

    dispose = autorun(() => {
        const { showsPrite } = homeStore;
        this.particles.visible = showsPrite;
    });

    //带倒影的标签 北京
    beijingLabel = (() => {
        const beijingLabel = new HtmlLableReflextion(`
            <div style="color:#ffffff;text-align:center;font-size: 100px;" >
                <div>北京<div>
                <div style="font-size:50px;" >beijing<div>
            </div>
        `);
        beijingLabel.name = "北京";
        beijingLabel.position.set(0, 0, 5);
        this.add(beijingLabel);
        return beijingLabel;
    })();

    //带倒影的标签 天津
    tianjianLabel = (() => {
        const tianjianLabel = new HtmlLableReflextion(`
                <div style="color:#ffffff;font-size: 50px;padding: 10px;border-radius: 4px;background: rgba(0, 0, 0, 0.6);">
                    <img src='${labelIconPNG}' style="vertical-align: middle;width:50px;height:50px;" />
                    <span style="vertical-align: middle;" >天津</span>
                <div>
            `);
        tianjianLabel.name = "天津";
        tianjianLabel.position.set(5, 0, 3.9);
        this.add(tianjianLabel);
        return tianjianLabel;
    })();

    //带倒影的标签 唐山
    tangshanLabel = (() => {
        const tangshanLabel = new HtmlLableReflextion(`
                <div style="color:#ffffff;font-size: 50px;padding: 10px;border-radius: 4px;background: rgba(0, 0, 0, 0.6);">
                    <img src='${labelIconPNG}' style="vertical-align: middle;width:50px;height:50px;" />
                    <span style="vertical-align: middle;" >唐山</span>
                <div>
            `);

        tangshanLabel.position.set(9, 0, 1.9);
        this.add(tangshanLabel);
        return tangshanLabel;
    })();

    //带倒影的标签 保定
    baodingLabel = (() => {
        const baodingLabel = new HtmlLableReflextion(`
                <div style="color:#ffffff;font-size: 50px;padding: 10px;border-radius: 4px;background: rgba(0, 0, 0, 0.6);">
                    <img src='${labelIconPNG}' style="vertical-align: middle;width:50px;height:50px;" />
                    <span style="vertical-align: middle;" >保定</span>
                <div>
            `);

        baodingLabel.position.set(-6, 0, 4.9);
        this.add(baodingLabel);
        return baodingLabel;
    })();

    //带倒影的标签 张家口
    zhangjiakouLabel = (() => {
        const zhangjiakouLabel = new HtmlLableReflextion(`
                <div style="color:#ffffff;font-size: 50px;padding: 10px;border-radius: 4px;background: rgba(0, 0, 0, 0.6);">
                    <img src='${labelIconPNG}' style="vertical-align: middle;width:50px;height:50px;" />
                    <span style="vertical-align: middle;" >张家口</span>
                <div>
            `);

        zhangjiakouLabel.position.set(-6, 0, -9.1);
        // keyContorls.addEventListener("change", (e: any) => {
        //     zhangjiakouLabel.position.add(e.direction);
        //     console.log(zhangjiakouLabel.position.toArray().map(v => round(v, 3)).join(", "));
        // });
        this.add(zhangjiakouLabel);
        return zhangjiakouLabel;
    })();

    async init() {
        await Promise.all([
            this.beijingLabel.init(),
            this.tianjianLabel.init(),
            this.tangshanLabel.init(),
            this.baodingLabel.init(),
            this.zhangjiakouLabel.init(),
            this.transition.set({ s: 1 })
        ])
    }

    //创建点
    point = (() => {
        const gridSize = 100;
        const pointSize = 0.2;
        const pointColor = 0x28373a;
        const pointLayout = {
            row: 200,
            col: 200,
        };
        const pointBlending = NormalBlending;
        const diffuse = false;
        const rows = pointLayout.row
        const cols = pointLayout.col
        const positions = new Float32Array(rows * cols * 3)
        for (let i = 0; i < rows; i++) {
            for (let j = 0; j < cols; j++) {
                let x = (i / (rows - 1)) * gridSize - gridSize / 2
                let y = -0.1;
                let z = (j / (cols - 1)) * gridSize - gridSize / 2
                let index = (i * cols + j) * 3
                positions[index] = x
                positions[index + 1] = y
                positions[index + 2] = z
            }
        }
        var geometry = new BufferGeometry()
        geometry.setAttribute("position", new BufferAttribute(positions, 3))

        let material = new PointsMaterial({
            size: pointSize,
            sizeAttenuation: true,
            color: pointColor,
            blending: pointBlending,
        })
        const particles = new Points(geometry, material)
        particles.frustumCulled = false;
        this.diffuseShader(material);
        this.add(particles);
        return particles
    })();

    // 创建点材质
    diffuseShader(material: PointsMaterial) {
        const position = new Vector3(0, 0, 0);
        const gridSize = 100;
        const gridDivision = 20;
        const gridColor = 0x28373a;
        const shapeSize = 1;
        const shapeColor = 0x8e9b9e;
        const pointSize = 0.2;
        const pointColor = 0x28373a;
        const pointLayout = {
            row: 200,
            col: 200,
        };
        const pointBlending = NormalBlending;
        const diffuse = false;
        const diffuseSpeed = 15.0;
        const diffuseColor = 3844268;
        const diffuseWidth = 10.0;
        material.transparent = true;
        material.onBeforeCompile = (shader: ShaderMaterial) => {
            this.pointShader = shader;

            shader.uniforms = {
                ...shader.uniforms,
                uTime: {
                    value: 0.0,
                },
                uSpeed: {
                    value: diffuseSpeed,
                },
                uWidth: {
                    value: diffuseWidth,
                },
                uColor: {
                    value: new Color(diffuseColor),
                },
            };
            shader.vertexShader = shader.vertexShader.replace(
                "void main() {",
            /* glsl */ `
                varying vec3 vPosition;
                void main(){
                  vPosition = position;
              `
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                "void main() {",
            /* glsl */ `
                uniform float uTime;
                uniform float uSpeed;
                uniform float uWidth;
                uniform vec3 uColor;
                varying vec3 vPosition;
                void main(){
              `
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                "#include <opaque_fragment>",
            /* glsl */ `
                #ifdef OPAQUE
                diffuseColor.a = 1.0;
                #endif
                
                #ifdef USE_TRANSMISSION
                diffuseColor.a *= material.transmissionAlpha;
                #endif
                
                float r = uTime * uSpeed;
              
                float w = 0.0; 
                if(w>uWidth){
                  w = uWidth;
                }else{
                  w = uTime * 5.0;
                }
               
                vec2 center = vec2(0.0, 0.0); 
               
                float rDistance = distance(vPosition.xz, center);
                
                if(rDistance > r && rDistance < r + 2.0 * w) {
                  float per = 0.0;
                  if(rDistance < r + w) {
                    per = (rDistance - r) / w;
                    outgoingLight = mix(outgoingLight, uColor, per);
                  } else {
                    per = (rDistance - r - w) / w;
                    outgoingLight = mix(uColor, outgoingLight, per);
                  }
                  gl_FragColor = vec4(outgoingLight, diffuseColor.a);
                } else {
                  gl_FragColor = vec4(uColor, 0.3);
                }
              `
            );
        };
    }

    pointShader?: ShaderMaterial;

    clock = new Clock();

    maxTime = 5; // size / diffuseSpeed;

    updateMatrixWorld(force?: boolean | undefined): void {
        super.updateMatrixWorld(force);
        if (this.pointShader) {
            this.pointShader.uniforms.uTime.value += (this.clock.getDelta());
            if (this.pointShader.uniforms.uTime.value > this.maxTime) {
                this.pointShader.uniforms.uTime.value = 0;
            }
        }
    };

    transition = (() => {
        const transition = new Transition({ s: 0 });
        transition.setBezier([0, 0, 1, 1]);
        transition.setDuration(1000);
        transition.onChange(({ s }) => {
            this.annular1.scale.set(s, s, s);
            this.annular2.scale.set(s, s, s);
        });
        return transition;
    })();


}